/*
	Quantum Miracle #WCCChallenge "Illusion" 250125 
	https://openprocessing.org/sketch/2521668
	#generativeart #creativecoding #p5js

  Dear Raph and creative coding community,
	
	no real illusion but liked to make rotating wobbling circular rays with 
	anti cyclic color lerping of each restart random palette...
	
	Next step is converting curves in svg paths for #penplotter

	Join the Birb's Nest Discord for friendly creative coding community
	and future challenges and contributions: https://discord.gg/S8c7qcjw2b
	WCCC-Contributions: https://openprocessing.org/curation/78544
*/
// 在文件开头添加新的调色板
const palettes = [
    ["#264653", "#2a9d8f", "#e9c46a", "#f4a261", "#e76f51"],
    ["#001219", "#005f73", "#0a9396", "#94d2bd", "#ee9b00"],
    ["#03071e", "#370617", "#6a040f", "#9d0208", "#dc2f02"],
    ["#d8f3dc", "#b7e4c7", "#95d5b2", "#74c69d", "#52b788"],
    // 添加更多炫丽的配色
    ["#ff0080", "#ff00ff", "#8000ff", "#0080ff", "#00ffff"],
    ["#7400b8", "#6930c3", "#5e60ce", "#5390d9", "#48bfe3"],
    ["#ff006e", "#fb5607", "#ff3366", "#ff6b6b", "#4ecdc4"]
];

// 添加全局变量
let rotationSpeed = 0;
let pulseEffect = 0;
let numPts = 120; // 射线数量
let pal = []; // 当前使用的调色板
let da = PI / 8; // 角度增量
let S = 200; // 缩放因子
let radiArr = [0.2, 0.4, 0.6, 0.8, 1.0]; // 半径数组
let svgSplines = []; // SVG路径数组

function setup() {
    createCanvas(800, 800);
    colorMode(RGB);
    noFill();
    strokeWeight(1);
    // 随机选择一个调色板
    pal = palettes[floor(random(palettes.length))];
}

function draw() {
    blendMode(BLEND);
    background(32, 180); // 降低透明度产生拖尾效果
    
    // 添加全局旋转效果
    rotationSpeed += 0.001;
    pulseEffect = sin(frameCount * 0.02) * 0.3;

    push();
    translate(width / 2, height / 2);
    rotate(rotationSpeed);
    
    const d = noise(frameCount / 123) / 2;
    for (let i = 0; i < numPts; i++) {
        let svgSpline = [];
        beginShape();
        
        // 使用更复杂的颜色混合
        const baseColor = getClrFromPalette(
            pal,
            ((i + frameCount / 15) % pal.length) / pal.length
        );
        const pulseColor = color(255, 100);
        const finalColor = lerpColor(baseColor, pulseColor, abs(sin(frameCount * 0.01 + i * 0.1)) * 0.3);
        stroke(finalColor);
        strokeWeight(1 + sin(frameCount * 0.05 + i * 0.1) * 1.5); // 动态线条粗细

        for (let j = 0; j < radiArr.length; j++) {
            const na = (i / numPts) * TAU;
            const nr = j;
            const ns = noise(
                345345 + cos(na) * nr,
                123412 + sin(na) * nr,
                frameCount / 120
            );

            // 增强动态效果
            const ra = (j % 2 == 0 ? da : -da) * sin(frameCount / 120 + i * 0.1);
            const ang = (i / numPts) * TAU + ra + frameCount / 240;
            const r = S * radiArr[j] * map(ns, 0, 1, d, 1 - d) * (1 + pulseEffect);
            const x = cos(ang) * r;
            const y = sin(ang) * r;
            curveVertex(x, y);
            svgSpline.push({ x, y });
        }
        endShape();
        svgSplines.push(svgSpline);
    }
    pop();

    // 添加闪光效果
    if (random(1) < 0.03) {
        blendMode(ADD);
        stroke(255, 30);
        strokeWeight(random(2, 5));
        const angle = random(TWO_PI);
        const len = random(width * 0.1, width * 0.4);
        const x1 = width/2 + cos(angle) * len;
        const y1 = height/2 + sin(angle) * len;
        line(width/2, height/2, x1, y1);
    }
}

function getClrFromPalette(palette, fr, al = 0) {
  const ci = fr * palette.length;
  const clr1 = color(palette[(~~ci + 0) % palette.length]);
  const clr2 = color(palette[(~~ci + 1) % palette.length]);
  if (al) {
    clr1.setAlpha(al);
    clr2.setAlpha(al);
  }
  return lerpColor(clr1, clr2, fract(ci));
}

function mouseClicked() {
  if (mouseButton != RIGHT) setup();
}

function keyPressed() {
  // generate svg output
  if (key === "s") {
    const svgGrps = [];
    for (let i = 0; i < pal.length; i++) {
      svgGrps[i] = "";
    }
    const w_h = ~~(width / 2);
    const h_h = ~~(height / 2);
    for (let j = 0; j < svgSplines.length; j++) {
      const svgSpline = svgSplines[j];
      let svgLine = `<polyline points="`;
      for (let i = 0; i < svgSpline.length - 3; i++) {
        const p1 = svgSpline[i + 0];
        const p2 = svgSpline[i + 1];
        const p3 = svgSpline[i + 2];
        const p4 = svgSpline[i + 3];
        for (let f = 0.1; f <= 1; f += 0.1) {
          const x = curvePoint(p1.x, p2.x, p3.x, p4.x, f) + w_h;
          const y = curvePoint(p1.y, p2.y, p3.y, p4.y, f) + h_h;
          svgLine += `${nf(x, 0, 1)} ${nf(y, 0, 1)} `;
        }
      }
      svgLine += `" />\n`;
      svgGrps[j % pal.length] += svgLine;
    }

    let svgStr = `<svg width="${width}" height="${width}" version="1.1" xmlns="http://www.w3.org/2000/svg">\n`;
    for (let i = 0; i < svgGrps.length; i++) {
      svgStr += `<g stroke="${pal[i]}" fill="none">\n${svgGrps[i]}\n</g>\n`;
    }
    svgStr += `</svg>`;

    save(svgStr.split("\n"), "epi_quantum_rays.svg.txt");
  }
}
